/*
 * 
 *  This file is part of Sourceprojects.org Lycia Copyright 2010 noctarius
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 * 
 */
package org.sourceprojects.lycia.internal.configuration;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.sourceprojects.lycia.LyciaConfigurator;
import org.sourceprojects.lycia.LyciaParser;
import org.sourceprojects.lycia.QualifiedName;
import org.sourceprojects.lycia.TagDefinitionParser;
import org.sourceprojects.lycia.annotations.Tag;
import org.sourceprojects.lycia.annotations.Validator;
import org.sourceprojects.lycia.internal.validation.ConstraintValidatorUtils;
import org.sourceprojects.lycia.internal.validation.PropertyDescriptor;
import org.sourceprojects.lycia.internal.validation.ValidatingTagDefinitionParser;
import org.w3c.dom.Element;

/**
 * 
 * @author noctarius
 * @since 1.9.1
 * 
 * @param <B>
 */
public class ValidationAwareXmlParserConfigurator<B> extends
		AnnotatedXmlParserConfigurator<B> {

	public ValidationAwareXmlParserConfigurator(final LyciaParser<B> xmlParser,
			final LyciaConfigurator<B> parent) {
		super(xmlParser, parent);
	}

	@Override
	@SuppressWarnings("unchecked")
	public List<TagDefinitionParser<B>> findTagDefinitionParsers(
			final QualifiedName localElement, final Element element) {

		final List<TagDefinitionParser<B>> parsers = super
				.findTagDefinitionParsers(localElement, element);

		final Iterator<TagDefinitionParser<B>> iterator = parsers.iterator();
		while (iterator.hasNext()) {
			final TagDefinitionParser<B> parser = iterator.next();

			if (parser instanceof ValidatingTagDefinitionParser<?>) {
				final PropertyDescriptor<B>[] properties = ((ValidatingTagDefinitionParser<B>) parser)
						.getPropertyDescriptor();

				if (!ConstraintValidatorUtils.checkConstraints(properties,
						element, getXmlParser())) {

					iterator.remove();
				}
			}

			final Tag[] tags = parser.getTagAnnotations();
			for (final Tag tag : tags) {
				final PropertyDescriptor<B>[] properties = findValidators(tag);
				if (!ConstraintValidatorUtils.checkConstraints(properties,
						element, getXmlParser())) {

					iterator.remove();
				}

			}
		}

		return parsers;
	}

	@SuppressWarnings("unchecked")
	private PropertyDescriptor<B>[] findValidators(final Tag tag) {
		if (tag.validations() == null || tag.validations().length == 0) {
			return new PropertyDescriptor[0];
		}

		List<PropertyDescriptor<B>> descriptors = new ArrayList<PropertyDescriptor<B>>();

		for (final Validator validator : tag.validations()) {
			final Class<?> impl = validator.value();
			final PropertyDescriptor<B>[] propertyDescriptors = ConstraintValidatorUtils
					.buildProperDescriptors(impl);

			descriptors = addAll(descriptors, propertyDescriptors);
		}

		return descriptors.toArray(new PropertyDescriptor[descriptors.size()]);
	}

	private List<PropertyDescriptor<B>> addAll(
			final List<PropertyDescriptor<B>> list,
			final PropertyDescriptor<B>[] propertyDescriptors) {

		for (final PropertyDescriptor<B> descriptor : propertyDescriptors) {
			list.add(descriptor);
		}

		return list;
	}

}
